package com.wsz.user.consumer;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wsz.pojo.FriendId;
import com.wsz.pojo.Message;
import com.wsz.pojo.UserInfo;
import com.wsz.user.mapper.FriendIdMapper;
import com.wsz.user.mapper.MessageMapper;
import com.wsz.user.mapper.UserInfoMapper;
import com.wsz.utils.TokenUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;

@Component
@ServerEndpoint("/websocket/qq/{token}")  // 注意不要以'/'结尾
public class WebSocketQQ {

    public static final ConcurrentHashMap<String, WebSocketQQ> users = new ConcurrentHashMap<>();//存储当前所有用户的websocket 线程安全
    private static final CopyOnWriteArraySet<UserInfo> userlist = new CopyOnWriteArraySet<>();//匹配池  线程安全

    private static final Logger log = LoggerFactory.getLogger(WebSocketQQ.class);

    private UserInfo user;//当前websocket 用户

    private static UserInfoMapper userInfoMapper;

    private static MessageMapper messageMapper;

    private static FriendIdMapper friendIdMapper;

    private Session session = null;//每个连接使用session维护

    @Autowired
    public void setUserInfoMapper(UserInfoMapper userInfoMapper) {
        WebSocketQQ.userInfoMapper = userInfoMapper;
    }

    @Autowired
    public void setMessageMapper(MessageMapper messageMapper) {
        WebSocketQQ.messageMapper = messageMapper;
    }

    @Autowired
    public void setFriendIdMapper(FriendIdMapper friendIdMapper) {
        WebSocketQQ.friendIdMapper = friendIdMapper;
    }

    //用户使用聊天时将其session加入在线用户池；
    @OnOpen
    public void onOpen(Session session, @PathParam("token") String token) {
        // 建立连接
        this.session = session;
        try {
            String userId = TokenUtils.getUserId(token);
            this.user = userInfoMapper.selectById(userId);

            if (this.user != null) {
                users.put(userId, this);
                userlist.add(this.user);
            } else this.session.close();
            sendUsers("userlist", userlist);
            sendFriend();
            sendOnline();
        } catch (Exception e) {
            throw new RuntimeException("token 不合法！！！");
        }
    }

    //退出时将用户从线程池删除
    @OnClose
    public void onClose() {
        // 关闭链接
        if (this.user != null) {
            users.remove(this.user.getId());
            userlist.remove(this.user);
            sendUsers("close",this.user.getId());
        }
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        // 从Client接收消息
        JSONObject Model = JSONObject.parseObject(message);
        String event = Model.getString("event");

        log.info("Model:{}", Model);
        if ("send-msg".equals(event)) {
            JSONObject data = (JSONObject) Model.get("data");
            String content = data.getString("content");
            String uid = this.user.getId();
            String fId = data.getString("fId");
            log.info("fid{}", fId);
            Message messageInfo = new Message();
            messageInfo.setMessage(content);
            messageInfo.setMId(uid);
            messageInfo.setYId(fId);
            messageMapper.insert(messageInfo);

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("event", "send-msg");
            jsonObject.put("data", messageInfo);
            DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            String datestr = format.format(messageInfo.getCreateTime());
            System.out.println(datestr);
            try {
                Date date = format.parse(datestr);
                messageInfo.setCreateTime(date);
            } catch (ParseException e) {
                e.printStackTrace();
            }

            if (users.get(fId) != null && !this.user.getId().equals(fId)) {
                sendMessageYou(jsonObject.toJSONString(), users.get(fId));
            }
            sendMessage(jsonObject.toJSONString());
        } else if ("get-msg".equals(event)) {
            this.hisMessage(Model);
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    //发送聊天记录
    private void hisMessage(JSONObject Model) {
        JSONObject data = (JSONObject) Model.get("data");
        String fId = data.getString("fId");

        List<Message> messages = new ArrayList<>();

        List<Message> messages_m = messageMapper.selectList(new QueryWrapper<Message>().eq("m_id", this.user.getId()).eq("y_id", fId));
        if (!this.user.getId().equals(fId)) {
            List<Message> messages_y = messageMapper.selectList(new QueryWrapper<Message>().eq("y_id", this.user.getId()).eq("m_id", fId));
            for (Message m : messages_y) {
                messages.add(m);
            }
        }

        for (Message m : messages_m) {
            messages.add(m);
        }

        List<Message> collect = messages.stream().sorted(new Comparator<Message>() {
            @Override
            public int compare(Message o1, Message o2) {
                return o1.getCreateTime().compareTo(o2.getCreateTime());
            }
        }).collect(Collectors.toList());
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("event", "get-msglist");
        jsonObject.put("data", collect);
        sendMessage(jsonObject.toJSONString());
    }

    //发送当前用户的好友列表
    private void sendFriend() {
        List<FriendId> friendIds = friendIdMapper.selectList(new QueryWrapper<FriendId>().eq("u_id", this.user.getId()));

        List<String> onlineIds = new ArrayList<>();
        List<String> offlineIds = new ArrayList<>();

        for (FriendId friendId : friendIds) {
            String userId = friendId.getFId();
            if (users.get(userId) != null) {
                onlineIds.add(userId);
            } else {
                offlineIds.add(userId);
            }
        }

        JSONObject o = new JSONObject();

        o.put("event", "online-friend");
        if (onlineIds.size() != 0) {
            o.put("data", userInfoMapper.selectList(new QueryWrapper<UserInfo>().in("id", onlineIds)));
        } else {
            o.put("data", new ArrayList<>());
        }
        sendMessage(o.toJSONString());


        o.put("event", "offline-friend");
        if (offlineIds.size() != 0) {
            o.put("data", userInfoMapper.selectList(new QueryWrapper<UserInfo>().in("id", offlineIds)));
        } else {
            o.put("data", new ArrayList<>());
        }
        sendMessage(o.toJSONString());
    }

    private void sendOnline(){
        List<FriendId> friendIds = friendIdMapper.selectList(new QueryWrapper<FriendId>().eq("u_id", this.user.getId()));

        for (FriendId friendId : friendIds) {
            String userId = friendId.getFId();
            if (users.get(userId) != null) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("event","get-online-friend");
                jsonObject.put("data",this.user);
                sendMessageYou(jsonObject.toJSONString(), users.get(userId));
            }
        }
    }


    //辅助发送在线用户消息
    private void sendUsers(String event, Object data) {
        synchronized (this.session) {
            for (UserInfo user : userlist) {
                WebSocketQQ qq = users.get(user.getId());
                try {
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("event", event);
                    jsonObject.put("data", data);
                    qq.session.getBasicRemote().sendText(jsonObject.toJSONString());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    //辅助消息发生方法给给定用户
    private void sendMessageYou(String message, WebSocketQQ webSocketQQ) {
        synchronized (this.session) {
            try {
                webSocketQQ.session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    //辅助消息发生方法给自身
    private void sendMessage(String message) {
        synchronized (this.session) {
            try {
                this.session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
